// Package models 模型通用属性和方法
package cm

import (
	"encoding/json"
	"github.com/spf13/cast"
	"gorm.io/gorm"
	"learn/pkg/database"
	"learn/pkg/hepler"
	"learn/pkg/logger"
	"reflect"
	"strings"
)

type BaseModel struct {
	BaseModelId
	BaseModelFiled `gorm:"-"`
}

type CommonTimestampsField struct {
	CreateAt  MyTime `gorm:"column:create_at;index;type:datetime;<-:false" json:"create_at,omitempty"`
	UpdatedAt MyTime `gorm:"column:updated_at;index;type:datetime;<-:false" json:"updated_at,omitempty"`
}

func (obj *BaseModel) Db() *gorm.DB {

	db := database.DB.Debug().Select(obj.GetSelectFile())
	if hepler.Empty(obj.Page) == false {
		db = db.Offset((obj.Page - 1) * obj.PageSize).Limit(obj.PageSize)
	}

	if hepler.Empty(obj.OrderBy) == false {
		db = db.Order(obj.OrderBy)
	}

	if hepler.Empty(obj.GetSelectFile()) == false {
		db = db.Select(obj.GetSelectFile())
	}

	if hepler.Empty(obj.WhereSql) == false && hepler.Empty(obj.WhereData) {
		wheredata := make(map[string]interface{})
		if err := json.Unmarshal(obj.WhereData, &wheredata); err != nil {
			db = db.Where(obj.WhereSql, wheredata)
		}
	}

	return db
}

func (obj *BaseModel) StructToMap(s interface{}) map[string]interface{} {
	v := reflect.ValueOf(s)
	if v.Kind() == reflect.Ptr {
		v = v.Elem()
	}

	if v.Kind() != reflect.Struct {
		logger.Error("db Err: input must be a struct or struct pointer")
		return nil
	}

	m := make(map[string]interface{})
	t := v.Type()

	var fileName string
	for i := 0; i < v.NumField(); i++ {
		f := v.Field(i)

		if jsonTag := t.Field(i).Tag.Get("json"); jsonTag != "" {
			if strings.Contains(jsonTag, ",") {
				fileName = strings.Split(jsonTag, ",")[0]
			} else {
				fileName = jsonTag
			}
		} else {
			continue
		}
		if !f.CanInterface() {
			continue
		}
		m[fileName] = f.Interface()
	}

	return m
}

func (obj *BaseModel) StructSliceToMapSlice(slice interface{}) []map[string]interface{} {
	s := reflect.ValueOf(slice)
	if s.Kind() != reflect.Slice {
		return nil
	}

	m := make([]map[string]interface{}, s.Len())
	for i := 0; i < s.Len(); i++ {
		m[i] = make(map[string]interface{})
		val := s.Index(i).Interface()
		t := reflect.TypeOf(val)

		for j := 0; j < t.NumField(); j++ {
			field := t.Field(j)
			jsonTag := field.Tag.Get("json")

			sonStruct := reflect.ValueOf(val).Field(j)
			if sonStruct.Kind() == reflect.Struct {
				if sonMap := obj.StructToMap(sonStruct.Interface()); m != nil {
					for sonKey, sonVal := range sonMap {
						m[i][sonKey] = cast.ToString(sonVal)
					}
				}
			} else {
				if jsonTag != "" {
					m[i][jsonTag] = reflect.ValueOf(val).Field(j).Interface()
				}
			}
		}
	}

	return m
}
